package edu.cs.usask.ca.silver.plugin.rcp.dialogs.create;

import java.io.File;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;

import edu.cs.usask.ca.silver.api.persistence.StorageI;
import edu.cs.usask.ca.silver.businesslogic.ids.ModelVersionID;
import edu.cs.usask.ca.silver.businesslogic.ids.ParameterID;
import edu.cs.usask.ca.silver.businesslogic.ids.ScenarioCollectionID;
import edu.cs.usask.ca.silver.businesslogic.ids.ScenarioID;
import edu.cs.usask.ca.silver.plugin.rcp.components.SilverPreferenceEntries;
import edu.cs.usask.ca.silver.plugin.rcp.dao.SilverBusinessLogicController;
import edu.cs.usask.ca.silver.plugin.rcp.jobs.LoggerReportScheduler;

public class CreateScenarioDialog extends Dialog {
	
	private static Logger logger = Logger.getLogger(CreateScenarioDialog.class);

	private Text scenarioNameText;
	private Text scenarioCreatorText;
	private Text scenarioDescriptionText;
	private List listAssociatedFiles;

	private String scenarioName = "";
	private String scenarioCreator = "";
	private String scenarioDescription = "";
	private Boolean selectedAssociates = true;
	private String[] associateFiles;

	private final ScenarioCollectionID scenarioCollectionID;
	private ModelVersionID versionID;
	private final StorageI myStorage;

	public CreateScenarioDialog(Shell shell,
			ScenarioCollectionID curScenarioCollectionId, StorageI storage) {
		super(shell);
		setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE);
		this.scenarioCollectionID = curScenarioCollectionId;
		this.myStorage = storage;
	}

	@Override
	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
		newShell.setText("Create New Scenario");
	}

	@Override
	protected Control createDialogArea(Composite parent) {

		final Composite compositeTopLevel = new Composite(parent, SWT.NONE);
		compositeTopLevel.setLayout(new GridLayout(3, false));

		Label scenarioNameLabel = new Label(compositeTopLevel, SWT.NONE);
		scenarioNameLabel.setText("&Name:");

		scenarioNameText = new Text(compositeTopLevel, SWT.BORDER);
		GridData gridData = new GridData();
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalSpan = 2;
		scenarioNameText.setLayoutData(gridData);

		Label scenarioCreatorLabel = new Label(compositeTopLevel, SWT.NONE);
		scenarioCreatorLabel.setText("&Creator:");
		gridData = new GridData();
		gridData.verticalAlignment = SWT.TOP;
		scenarioCreatorLabel.setLayoutData(gridData);

		scenarioCreatorText = new Text(compositeTopLevel, SWT.BORDER);
		gridData = new GridData();
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.horizontalSpan = 2;
		scenarioCreatorText.setLayoutData(gridData);
		scenarioCreatorText.setText(SilverBusinessLogicController
				.getPreferenceEntry(SilverPreferenceEntries.USER_LAST_NAME));

		Label scenarioDescriptionLabel = new Label(compositeTopLevel, SWT.NONE);
		scenarioDescriptionLabel.setText("&Description:");
		gridData = new GridData();
		gridData.verticalAlignment = SWT.TOP;
		scenarioDescriptionLabel.setLayoutData(gridData);

		scenarioDescriptionText = new Text(compositeTopLevel, SWT.BORDER
				| SWT.WRAP | SWT.MULTI);
		gridData = new GridData();
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.minimumHeight = scenarioDescriptionText.getLineHeight() * 5;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalSpan = 2;
		scenarioDescriptionText.setLayoutData(gridData);

		// Associate Files

		Group associateFilesGroup = new Group(compositeTopLevel, SWT.NONE);
		associateFilesGroup.setText("Associate Files");
		gridData = new GridData();
		gridData.verticalIndent = 10;
		gridData.horizontalSpan = 3;
		gridData.horizontalAlignment = SWT.FILL;
		associateFilesGroup.setLayoutData(gridData);
		associateFilesGroup.setLayout(new GridLayout(3, true));

		final Button associateFileCheckBox = new Button(associateFilesGroup,
				SWT.CHECK);
		associateFileCheckBox.setText("&Create with associate files.");
		associateFileCheckBox.setSelection(false);
		gridData = new GridData();
		gridData.horizontalSpan = 3;
		associateFileCheckBox.setLayoutData(gridData);

		final Label associateFileLabel = new Label(associateFilesGroup, SWT.END);
		associateFileLabel.setText("&List of associated files:");

		// Multiple-selection list
		listAssociatedFiles = new List(associateFilesGroup, SWT.MULTI
				| SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
		gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
		gridData.horizontalSpan = 3;
		listAssociatedFiles.setLayoutData(gridData);

		final Label listCountLabel = new Label(associateFilesGroup, SWT.LEFT);
		listCountLabel.setText(String.valueOf(listAssociatedFiles
				.getItemCount()) + " files added.");

		final Button removeFile = new Button(associateFilesGroup, SWT.PUSH
				| SWT.RIGHT);
		removeFile.setAlignment(SWT.CENTER);
		removeFile.setText("Remove");
		removeFile.setToolTipText("Remove the last added file from the list.");
		gridData = new GridData();
		gridData.horizontalAlignment = SWT.END;

		removeFile.setLayoutData(gridData);

		removeFile.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (listAssociatedFiles.getItemCount() == 0) {
					return;
				}
				listAssociatedFiles.remove(listAssociatedFiles.getItemCount() - 1);
			}
		});

		final Button loadFile = new Button(associateFilesGroup, SWT.PUSH
				| SWT.RIGHT);
		loadFile.setAlignment(SWT.CENTER);
		loadFile.setText("Add..");
		loadFile.setToolTipText("Add any types of files from system; the "
				+ "absolute file path will be added to the list");

		loadFile.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				FileDialog file = new FileDialog(compositeTopLevel.getShell(),
						SWT.OPEN);
				file.setFilterExtensions(new String[] { "*.*" });
				file.setFilterNames(new String[] { "Associate files (*.*)" });
				file.setText("Load Associate File:");
				listAssociatedFiles.add(file.open());
				listCountLabel.setText(String.valueOf(listAssociatedFiles
						.getItemCount()) + " files loaded.");
			}
		});

		/*
		 * Use check box to control whether user wants to add associate file
		 * with Project
		 */
		associateFileCheckBox.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				loadFile.setEnabled(associateFileCheckBox.getSelection());
				removeFile.setEnabled(associateFileCheckBox.getSelection());
				listAssociatedFiles.setEnabled(associateFileCheckBox
						.getSelection());
				associateFileLabel.setEnabled(associateFileCheckBox
						.getSelection());
				selectedAssociates = associateFileCheckBox.getSelection();
				listCountLabel.setEnabled(associateFileCheckBox.getSelection());
			}
		});
		loadFile.setEnabled(associateFileCheckBox.getSelection());
		removeFile.setEnabled(associateFileCheckBox.getSelection());
		listAssociatedFiles.setEnabled(associateFileCheckBox
				.getSelection());
		associateFileLabel.setEnabled(associateFileCheckBox
				.getSelection());
		selectedAssociates = associateFileCheckBox.getSelection();
		listCountLabel.setEnabled(associateFileCheckBox.getSelection());

		try {
			// get the model version version id associated with the current
			// scenario
			// collection
			versionID = (ModelVersionID) scenarioCollectionID
					.getParentObjectId(myStorage);

			// get the baseline scenario associated with this model version
			ScenarioID baseScenarioId = SilverBusinessLogicController
					.borrowMvObject().getBaselineScenarioId(versionID,
							myStorage);

			if (baseScenarioId != null) {
				SilverBusinessLogicController.returnLastMvObject();

				// get the baseline parameter ids associated with this model
				// version

				ParameterID[] baseParameterIds = SilverBusinessLogicController
						.borrowScenario().getParameterIds(baseScenarioId,
								myStorage);
				SilverBusinessLogicController.returnLastScenarioObject();

				// parameter values area starts

				Group parameterValuesGroup = new Group(compositeTopLevel,
						SWT.NONE);
				CreateScenarioTableContentProvider contentProvider = EstablishBaselineParameterValueTableAndReturnTableContentProvider(
						parameterValuesGroup, compositeTopLevel,
						baseScenarioId, baseParameterIds);

				// establish button for loading an existing simulation run (in
				// lieu
				// of running this

				EstablishAndConfigureLoadSimulationButton(
						baseScenarioId.getTypeFromDatabase(myStorage),
						baseScenarioId, parameterValuesGroup,
						compositeTopLevel, listAssociatedFiles, contentProvider);

			}
		} catch (Exception e) {
			LoggerReportScheduler.scheduleErrorLogging(logger,"Unexpected exception while trying to determine the type of simulation associated with scenario ",e);
		}

		// redraw it (we were having problems where was only partly drawn)
		return compositeTopLevel;
	} /* end of createDialogArea */

	private CreateScenarioTableContentProvider EstablishBaselineParameterValueTableAndReturnTableContentProvider(
			final Group parameterValuesGroup, final Composite composite,
			final ScenarioID baseScenarioId, ParameterID[] baseParameterIds) {
		GridLayout sPaneComp = new GridLayout(3, true);

		GridData mvPaneData = new GridData(GridData.FILL_BOTH);
		mvPaneData.horizontalSpan = 4;
		parameterValuesGroup.setLayoutData(mvPaneData);
		parameterValuesGroup.setLayout(sPaneComp);

		Label baseLineLabel = new Label(parameterValuesGroup, SWT.NONE);
		baseLineLabel
				.setText("&Baseline Scenario: Please Edit the Parameter Values and Comments as Desired");
		baseLineLabel.setLayoutData(new GridData(GridData.FILL, GridData.FILL,
				false, false, 3, 1));

		int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL
				| SWT.FULL_SELECTION | SWT.HIDE_SELECTION;
		Table table = new Table(parameterValuesGroup, style);
		GridData gridData1 = new GridData(GridData.FILL_BOTH);
		gridData1.grabExcessVerticalSpace = false;
		gridData1.horizontalSpan = 3;
		gridData1.heightHint = 150;
		table.setLayoutData(gridData1);
		table.setLinesVisible(true);
		table.setHeaderVisible(true);

		/* table that displays the baseline parameters to be edits */
		TableViewer paramData = new TableViewer(table);
		CreateScenarioTableContentProvider content = new CreateScenarioTableContentProvider(
				baseParameterIds, baseScenarioId, myStorage);
		paramData.setContentProvider(content);

		CreateScenarioTableColumnLabelProvider columnsLabels = new CreateScenarioTableColumnLabelProvider(
				this, baseScenarioId);
		columnsLabels.createColumns(paramData);

		paramData.getTable().setHeaderVisible(true);
		paramData.getTable().setLinesVisible(true);
		paramData.setInput(content);

		return content;
	}

	/**
	 * the data supplied to stored into local variable to be extracted using the
	 * get method by the CreateModelVersionAction class. This method checks to
	 * make sure that all the fields are filled out
	 * 
	 */
	@Override
	protected void okPressed() {

		scenarioName = scenarioNameText.getText();
		scenarioCreator = scenarioCreatorText.getText();
		scenarioDescription = scenarioDescriptionText.getText();

		if (scenarioName.isEmpty()) {
			MessageDialog.openError(getShell(), "Invalid Scenario Name",
					"Name field must not be blank.");
			return;
		}
		
		if (scenarioCreator.isEmpty()) {
			MessageDialog.openError(getShell(), "Invalid Scenario Creator",
					"Creator field must not be blank.");
			return;
		}
		
		if (scenarioDescription.isEmpty()) {
			if (!MessageDialog
					.openConfirm(getShell(), "Empty Scenario Description",
							"Is it OK to leave the description empty for now?")) {
				return;
			}
		}

		// associated files
		if (selectedAssociates) {
			File temp;
			if (listAssociatedFiles.getItemCount() == 0) {
				if (MessageDialog
						.openConfirm(
								this.getParentShell(),
								"No Associate Files listed",
								"You checked to add associate files but did not add any to the list. OK to proceed?")) {
					selectedAssociates = false;
				} else {
					return;
				}
			} else {
				// check if files can be loaded
				for (int index = 0; index < listAssociatedFiles.getItemCount(); index++) {
					temp = new File(listAssociatedFiles.getItem(index));
					if (!temp.canRead()) {
						MessageDialog.openError(getShell(), "File Open Error",
								"Unable to open Associate File at "
										+ listAssociatedFiles.getItem(index));
						return;
					}
				}
			}

			associateFiles = listAssociatedFiles.getItems();
		}

		super.okPressed();

	} /* end of okPressed */

	private void EstablishAndConfigureLoadSimulationButton(
			final String strSimulationType,
			final ScenarioID templateScenarioId, final Group scenarioInfoGroup,
			final Composite compositeTopLevel, final List associatedFileList,
			final CreateScenarioTableContentProvider providerTableContent) {

		Button loadSimulationButton = EstablishLoadSimulationButton(
				strSimulationType, scenarioInfoGroup);

		loadSimulationButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				FileDialog fileDialog = new FileDialog(compositeTopLevel
						.getShell(), SWT.OPEN);
				fileDialog.setFilterExtensions(new String[] { "*.vdf" });
				fileDialog
						.setFilterNames(new String[] { "Trajectory files (*.vdf)" });
				fileDialog
						.setText("Reconstruct Multiple Scenarios from Existing Trajectory Files:");

				try {
					// Don't actually add in the file to the database yet --
					// just add to the associated files, and add it later in
					// createScenarioCommand.
					String strFile = fileDialog.open();
					// add this file to the list of associated files
					listAssociatedFiles.add(strFile);
					// get a handle to this file
					File addFile = new File(strFile);

					// We'd ideally like to return a Map<ParameterID, Double> ,
					// but this was causing a bizarre error
					// where the hash table wasn't working (see
					// CreateScenarioTableContentProvider)

					// ok, now that we've added the file, record the parameter
					// values associated with that file!
					Map<Integer, Double> map = SilverBusinessLogicController
							.borroweSilverServiceObject()
							.ExtractValuesForParametersFromVDFTrajectoryFile(
									templateScenarioId, addFile, myStorage);
					SilverBusinessLogicController
							.returnlastSilverServiceObject();
					// // reflect these values in the parameter value table
					providerTableContent.overrideParameterValues(map);

				} catch (Exception e1) {
					LoggerReportScheduler.scheduleErrorLogging(logger,"Error whie loading simulation button in creating a sceanrio", e1);
				}

			}

		});

	}

	public static Button EstablishLoadSimulationButton(
			final String strSimulationType,
			final Composite compositeSurroundingContext) {
		Button loadSimulationButton = new Button(compositeSurroundingContext,
				SWT.RIGHT);
		// only enable the button for simulation types that support trajectory
		// files

		// TODO: ***For easier modification, we should really abstract out this
		// test so that it occurs in a single
		loadSimulationButton.setVisible(strSimulationType
				.equalsIgnoreCase("VENSIM"));

		loadSimulationButton.setText("Load " + strSimulationType
				+ " Trajectory file");

		// runSimLabel.setBackground(top.getDisplay().getSystemColor(SWT.COLOR_RED));
		// arrange for how the button is to be laid out
		loadSimulationButton.setLayoutData(new GridData(GridData.END,
				GridData.CENTER, false, false));
		// set the tooltip
		loadSimulationButton
				.setToolTipText("Load a trajectory file for this scenario, and draw parameter values from it.");

		// editName.addSelectionListener(new
		// RenameButtonSelectionAdapter(parent, getModelObjectID(),
		// getModelObjectName())),

		return loadSimulationButton;
	}

	/**
	 * a method to get the new scenario name
	 * 
	 * @return String containing the scenario name
	 */
	public String getScenarioName() {
		return scenarioName;
	}

	/**
	 * a method to get the new scenario creator
	 * 
	 * @return String containing the scenario creator
	 */
	public String getScenarioCreator() {
		return scenarioCreator;
	}

	/**
	 * a method to get the new scenario description
	 * 
	 * @return String containing the scenario description
	 */
	public String getScenarioDescription() {
		return scenarioDescription;
	}

	/**
	 * a method to get the version id this scenario belongs
	 * 
	 * @return ModelVersionId
	 */
	public ModelVersionID getModelVersionID() {
		return versionID;
	}

	public ScenarioCollectionID getScenarioCollectionID() {
		return scenarioCollectionID;
	}

	/**
	 * this method returns the selection of check box for associate file group.
	 * Different Scenario creation method is initiated based on the user choice.
	 * 
	 * @return Boolean - whether check box is checked
	 */
	public Boolean getAssociateFileSelection() {
		return selectedAssociates;
	}

	/**
	 * a method to get the array of Strings containing a stack of associate file
	 * paths.
	 * 
	 * @return String[] containing a set of String; return null if no associate
	 *         files are added.
	 */
	public String[] getAssociateFileArray() {
		return associateFiles;
	}

} /* end of class */
